package com.hcms.admin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hcms.admin.dto.SysMenuOptionResponse;
import com.hcms.admin.dto.SysMenuRouteResponse;
import com.hcms.admin.dto.SysMenuTreeResponse;
import com.hcms.common.exception.ApiException;
import com.hcms.common.util.TreeUtil;
import com.hcms.mybatis.entity.SysMenu;
import com.hcms.mybatis.mapper.SysMenuMapper;
import com.hcms.admin.service.ISysMenuService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 后台菜单表 服务实现类
 * </p>
 *
 * @author achenxw@126.com
 * @since 2023-02-14
 */
@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements ISysMenuService {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private SysMenuMapper sysMenuMapper;


    @Override
    public List<SysMenu> getList() {
        logger.info("Run getList()");
        LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByAsc(SysMenu::getSort, SysMenu::getId);
        return sysMenuMapper.selectList(queryWrapper);
    }

    @Override
    public List<SysMenuTreeResponse> getTreeList() {
        logger.info("Run getTreeList()");
        LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByAsc(SysMenu::getSort, SysMenu::getId);
        List<SysMenu> sysMenus = sysMenuMapper.selectList(queryWrapper);
        List<SysMenuTreeResponse> results = sysMenus.stream().map(SysMenuTreeResponse::new).collect(Collectors.toList());
        return TreeUtil.builder(results, 0L);
    }

    @Override
    public SysMenu getView(Long id) {
        logger.info("Run getView()");
        return sysMenuMapper.selectById(id);
    }

    @Override
    public List<SysMenuOptionResponse> getOptions() {
        logger.info("Run getOptions()");
        LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(SysMenu::getId, SysMenu::getParentId, SysMenu::getMetaTitle);
        queryWrapper.orderByAsc(SysMenu::getSort);
        List<SysMenu> sysMenus = sysMenuMapper.selectList(queryWrapper);
        List<SysMenuOptionResponse> results = sysMenus.stream().map(SysMenuOptionResponse::new).collect(Collectors.toList());
        return TreeUtil.builder(results, 0L);
    }

    @Override
    public List<SysMenuRouteResponse> getRoutes() {
        logger.info("Run getRoutes()");
        LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysMenu::getMenuType, SysMenu.MENU_TYPE_NAV);
        queryWrapper.orderByAsc(SysMenu::getSort, SysMenu::getId);
        List<SysMenu> sysMenus = sysMenuMapper.selectList(queryWrapper);
        List<SysMenuRouteResponse> results = sysMenus.stream().map(SysMenuRouteResponse::new).collect(Collectors.toList());
        return TreeUtil.builder(results, 0L);
    }

    @Override
    public int createItem(SysMenu entity) {
        logger.info("Run createItem()");
        //获取父级记录数据
        entity.setId(null);
        entity.setIdList(getIdList(entity.getParentId()));
        entity.setCreateTime(new Date());
        return sysMenuMapper.insert(entity);
    }

    @Override
    public int updateItem(Long id, SysMenu entity) {
        logger.info("Run updateItem(), id={}", id);
        entity.setId(id);
        entity.setIdList(getIdList(entity.getParentId()));
        //校验parentId，防止脏数据
        checkParentId(id, entity.getParentId());
        int count = sysMenuMapper.updateById(entity);
        if (count > 0) {
            //更新子记录的idList字段
            updateChildrenIdList(entity);
        }
        return count;
    }

    @Override
    public int deleteItem(String ids) {
        logger.info("Run deleteItem, ids={}", ids);
        String[] split = ids.split(",");
        List<String> list = Arrays.asList(split);
        List<Long> delIds = list.stream().map(Long::new).collect(Collectors.toList());
        //评断是否有子记录
        LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(SysMenu::getParentId, delIds);
        List<SysMenu> sysMenus = sysMenuMapper.selectList(queryWrapper);
        if (sysMenus.size() > 0) {
            logger.error("A child record cannot be deleted");
            throw new ApiException("有子记录不可删除");
        }
        return sysMenuMapper.deleteBatchIds(delIds);
    }

    /**
     * 根据 parentId 生成 idList
     */
    private String getIdList(Long parentId) {
        logger.info("Run getIdList(), parentId={}", parentId);
        String idList;
        if (parentId > 0) {
            SysMenu parentMenu = getView(parentId);
            if (parentMenu != null) {
                idList = parentMenu.getIdList() + "," + parentMenu.getId();
            } else {
                logger.error("The parent record does not exist");
                throw new ApiException("父级记录不存在");
            }
        } else {
            idList = "0";
        }
        return idList;
    }

    /**
     * 更新子记录的idList字段
     */
    private void updateChildrenIdList(SysMenu parentMenu) {
        LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysMenu::getParentId, parentMenu.getId());
        List<SysMenu> children = sysMenuMapper.selectList(queryWrapper);
        for (SysMenu child : children) {
            String idList = parentMenu.getIdList() + "," + parentMenu.getId();
            if (!idList.equals(child.getIdList())) {
                child.setIdList(idList);
                int count = sysMenuMapper.updateById(child);
                if (count > 0) {
                    updateChildrenIdList(child);
                }
            }
        }
    }

    /**
     * 校验parentId层级关系，防止脏数据
     */
    private void checkParentId(Long id, Long parentId) {
        logger.info("Run checkParentId(), id={}, parentId={}", id, parentId);
        List<SysMenu> childrenMenu = sysMenuMapper.selectChildrenMenu(id);
        List<Long> idsList = childrenMenu.stream().map(SysMenu::getId).collect(Collectors.toList());
        if (id.equals(parentId) || idsList.contains(parentId)) {
            logger.error("The parent-child field hierarchy is incorrect");
            throw new ApiException("父子字段层级关系错误");
        }
    }

}
